package cn.sjtu.data_structure.array;

import java.util.Arrays;

/**
 * @author syo 2319615164@qq.com
 * @description 动态数组
 * @date 2024/5/13
 * @Copyright syo
 */
public class ArrayList<E> {

    // 默认容量
    private static final int DEFAULT_CAPACITY = 10;

    // 默认数组
    private static final Object[] DEFAULT_CAPACITY_EMPTY_ELEMENT_DATA = {};

    // 元素缓存区
    private Object[] elementData;

    // 元素个数
    private int size;

    // 无参构造函数
    public ArrayList() {
        this.elementData = DEFAULT_CAPACITY_EMPTY_ELEMENT_DATA;
    }

    // 有参构造函数
    public ArrayList(int initialCapacity) {
        if (initialCapacity == 0) {
            this.elementData = DEFAULT_CAPACITY_EMPTY_ELEMENT_DATA;
        } else if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else {
            throw new IllegalArgumentException(
                    "initialCapacity" + initialCapacity + "参数不合法！"
            );
        }
    }

    // 添加元素
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);
        elementData[size++] = e;
        return true;
    }

    // 确保容量至少为minCapacity
    private void ensureCapacityInternal(int minCapacity) {
        // 如果是第一次扩容则选择默认容量和最小容量的最大值
        if (elementData == DEFAULT_CAPACITY_EMPTY_ELEMENT_DATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            elementData = new Object[minCapacity];
        }

        // 如果数组不是空则走下面扩容逻辑
        ensureExplicitCapacity(minCapacity);
    }

    // 显式判断是否扩容
    private void ensureExplicitCapacity(int minCapacity) {
        // 判断是否真的需要扩容
        if (minCapacity > elementData.length) {
            grow(minCapacity);
        }
    }

    // 真正扩容
    // 考虑最小容量为正
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - Integer.MAX_VALUE + 8 > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > Integer.MAX_VALUE - 8) ?
                Integer.MAX_VALUE :
                Integer.MAX_VALUE - 8;
    }

}
